package demo.java.lang;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.util.*;
import java.util.stream.Stream;

public class StringDemo {

    static Logger logger = LoggerFactory.getLogger(StringDemo.class);
    public static final String UTF8 = "UTF-8";


    @Test
    public void stringBuilder() {
        List<String> list = Arrays.asList("a", "b", "c", "d", null);
        StringBuilder sb = new StringBuilder();
        for (String string : list) {
            sb.append(string).append(",");
        }

        System.out.println(sb.toString());
        System.out.println(sb.deleteCharAt(sb.length() - 1));
    }

    @Test
    public void endWith() {
        String s = "导入用户.csv";
        boolean b = s.endsWith(".csv");
        System.out.println(b);

        String a = "[2024-08-07 20:17:16 802] [WARN] [com.ximalaya.mobile.album.log.AlbumLogMqService:sendMq:44] [http-nio-6273-exec-7] AlbumLogMqService:json{\"begTime\":1723033036755,\"endTime\":1723033036755,\"methodName\":\"/mobile-album/album/plant/grass/ts-1722996413565\",\"newContentMap\":{\"109941411\":{\"openDebug\":false,\"openHeadTag\":false,\"urlMappers\":[]}},\"oldContentMap\":{\"109941411\":{\"openDebug\":false,\"openHeadTag\":false,\"urlMappers\":[]}},\"operator\":\"60bcdc23-1d3d-38fe-937a-769c52db8213\",\"otherMap\":{\"currentUserId\":109941411},\"paramMap\":{\"param\":{\"ac\":[\"WIFI\"],\"albumId\":[\"4333341\"],\"device\":[\"android\"],\"identity\":[\"podcast\"],\"isAsc\":[\"true\"],\"isQueryInvitationBrand\":[\"true\"],\"isVideoAsc\":[\"true\"],\"pageSize\":[\"50\"],\"source\":[\"0\"],\"supportWebp\":[\"true\"]},\"client\":{\"bundleId\":\"com.ximalaya.ting.android\",\"device\":\"android\",\"deviceId\":\"60bcdc23-1d3d-38fe-937a-769c52db8213\",\"header\":{\"content-length\":\"0\",\"g_a_ui\":\"109941411_0\",\"x-gateway-sample\":\"254664056849433600\",\"cookie\":\"1&_device=android&60bcdc23-1d3d-38fe-937a-769c52db8213&9.2.84;1&_token=109941411&01E33000240C3155DED9A35A7034FA155E307C22AD4AA134442E4EDE5A28EF8A6D343248B8AC100Mb3d36c1F48EB094_;channel=default;impl=com.ximalaya.ting.android;osversion=34;fp=00111264432322b21vv49033194030a210112200100010111101441024061;device_model=V2338A;XIM=;c-oper=%E6%9C%AA%E7%9F%A5;net-mode=WIFI;res=1260%2C2680;AID=YmZjYmQyNzEyOTVkZjQwOQ;manufacturer=vivo;XD=9wh5UDXQa0bl4ep4fa9tcn4R3kl10SoskCI8dJVYoFZ7cc8HLVKWSfF0Ot+m5FCTb1eTfJqJUwMGxIfhc6JQFoEC4/xwzvk6ZuI79p/6sGwCQ3cSTzqGYc3UeIzZucO2;umid=635d24f8d344af10c19d81dfa82ac5cbod;xm_grade=0;specialModeStatus=0;ao=1GRk0uHaFJoI7m9TtwBnXX%2Bssid2p2NxUc06QlK8ptPJi6kVIyYQoR8lioissSqpG4tdiMKwJpLmGD4Qke7vj3JpzZ36XGKmHxy9V9VSv9A%3D;newChannelId=yz-vivo; domain=.ximalaya.com; path=/; freeFlowType=0; minorProtectionStatus=0; pcdnFree=0\",\"accept\":\"*/*\",\"cookie2\":\"$version=1\",\"x-real-ip\":\"43.247.101.196\",\"x-gw-serviceid\":\"/album/plant/grass/{w}\",\"myheadtag\":\"myHeadTag\",\"x-real-port\":\"50769\",\"host\":\"mobile.ximalaya.com\",\"connection\":\"close\",\"x-tk\":\"TACZrLWvWC83CMdPTj-k3p2nFLbghOxdlu1Qw5_Swq2PSsXccqbw8T3Uk9fPRmH7fxWRLJldRpwCtG-VBgM_2AgekUzGKpjb20ueGltYWxheWEudGluZy5hbmRyb2lkITEuMy4yMyE5LjIuNzUuMyFiPXBsYXlUcmFjayZzPWFsYnVtUGFnZSZ1PTEwOTk0MTQxMQ\",\"x-server-protocol\":\"HTTP/1.1\",\"accept-encoding\":\"gzip, deflate, br\",\"user-agent\":\"ting_9.2.75(V2338A,Android34)\"},\"token\":\"01E33000240C3155DED9A35A7034FA155E307C22AD4AA134442E4EDE5A28EF8A6D343248B8AC100Mb3d36c1F48EB094_\",\"uid\":\"109941411\",\"userAgent\":\"ting_9.2.75(V2338A,Android34)\",\"version\":\"9.2.84\"}},\"traceId\":\"254664056849433600\",\"type\":\"user_album\"}";
        System.out.println(a.getBytes().length);
    }

    @Test
    public void stringJoiner() {
        StringJoiner sj = new StringJoiner(",");
        sj.add("a").add("b").add("c");
        logger.info(sj.toString());

        String[] array = {"a", "b", "c"};
        logger.info(StringUtils.join(array, ","));

        System.out.println(StringUtils.join(array, "\n"));
        List<String> list = null;
        System.out.println(StringUtils.join(list, ","));

        Strings.join(Arrays.asList(array), ',');
    }

    @Test
    public void testSplit() {
        try {
            String a = "monitorUrl#";
            String[] array = a.split("#", 2);
            System.out.println(Arrays.toString(array) + ".length = " + array.length);
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        try {
            String a = "abc,x,y,z";
            String[] array = a.split(",", 2);
            System.out.println(Arrays.toString(array) + ".length = " + array.length);
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }

        try {
            String s = "a,b,,";
            String[] array = s.split(",");
            System.out.println(Arrays.toString(array) + ".length = " + array.length);
            array = s.split(",", 4);
            System.out.println(Arrays.toString(array) + ".length = " + array.length);
            array = s.split(",", 10);
            System.out.println(Arrays.toString(array) + ".length = " + array.length);
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        {
            String a = "null||null||123";
            String[] array = a.split("||");
            String[] arr = StringUtils.split(a, "||");
            System.out.println(Arrays.toString(array));
            System.out.println(Arrays.toString(arr));
            a = "0.15#0.1";
            System.out.println(Arrays.toString(a.split("#")));
        }
        {
            String a = "/var/log/pika/{port}/pika.ERROR";
            String[] arr = a.split("/");
            System.out.println(Arrays.toString(arr) + ", port = " + arr[4]);
        }

    }

    @Test
    public void split2() {
        String a = "monitor_server_load$sh-nh-b2-202-f2-clickhouse-56-212:8123";
        String[] array = a.split("\\$");
        System.err.println(array[0] + array[1]);
    }

    @Test
    public void split3() {
        String a = "kube-controller-manager,\n" +
                "kubectl-terminal,\n" +
                "kube-scheduler,\n" +
                "etcd-network-server,\n" +
                "etcd-event-server,\n" +
                "etcd-server,\n" +
                "mainstay-demo,\n" +
                "kube-apiserver,aa";
        String[] array = a.replace("\n", "").split(",");
        System.err.println(Arrays.toString(array));
        System.err.println(StringUtils.deleteWhitespace(a));
    }

    @Test
    public void testNull() throws IOException {
        Object o = null;
        System.out.println(o instanceof Object);
        String nil = null;
        System.out.println(nil);
    }

    /**
     * 这个用例验证 区分大小写
     */
    @Test
    public void contains() {
        System.out.println("A".contains("a"));

        System.out.println("{'status': True}".contains("true"));
        System.out.println("{'status': True}".contains("TRUE"));
        System.out.println("{'status': true}".contains("true"));
    }

    /**
     * <h1>字符串表</h1>
     * <p>
     * String有个常量池， Java 语言规范要求相同的（即包含相同序列的 Unicode 指针序列）字符串字面量必须指向相同的 String 实例。
     * 除此之外，在一个字符串实例上调用String.intern()方法的返回引用必须与字符串是字面量时的一样。
     * 注：String.intern()是一个native方法，不建议大面积使用。
     * HotspotJVM中interned字符串保存在字符串表中。字符串表是一个哈希表，保存着对象指针到符号的映射关系（也就是Hashtable），它被保存到永久代中。
     * 符号表和字符串表的实体都以规范的格式保存，保证每个实体都只出现一次。当类加载时，字符串字面量被编译器自动intern并加入到符号表。
     * 除此之外，String 类的实例可以调用 String.intern()显式地intern。 当调用
     * String.intern()方法时，如果符号表已经包含了这个字符串，那么就会返回符号表里的这个引用，如果不是，那么这个字符串就被加入到字符串表中同时返回这个引用。
     */
    @Test
    public void intern() {
        String a = "hello";
        String b = "hello world";
        String c = " world";
        String d = "hello";
        System.out.println(a == d);
        System.out.println("hello" == d);
        System.out.println(b == (a + c));
        System.out.println(b == (a + c).intern());
    }

    /**
     * IndexOutOfBoundsException异常
     */
    @Test
    public void testSubstr() {
        String basic = "Basic eG1seTp4bWx5MjAxNl8h";
        System.out.println(basic.substring(6));
        System.out.println(new String(Base64.getDecoder().decode(basic.substring(6).getBytes())));
        String a = "18217".substring(0, 7);
        System.out.println(a);

    }

    static void testStringBuilder() {
        StringBuilder sb = new StringBuilder("你好,");
        System.out.println(sb.toString());
        int length = sb.length();
        System.out.println("length:" + length);
        char idx0 = sb.charAt(0);
        System.out.println("charAt(0) :" + idx0);
        sb.deleteCharAt(length - 1);
        System.out.println(sb.toString());
    }

    /**
     * <li>replace的参数是char和CharSequence，即可以支持字符的替换，也支持字符串的替换
     * <li>replaceAll的参数是regex，即基于规则表达式的替换，比如，可以通过replaceAll("\\d",
     * "*")把一个字符串所有的数字字符都换成星号;
     * <p>
     * 相同点：都是全部替换，即把源字符串中的某一字符或字符串全部换成指定的字符或字符串。
     * 如果只想替换第一次出现的，可以使用replaceFirst()，这个方法也是基于规则表达式的替换，但与replaceAll()不同的是，只替换第一次出现的字符串；
     * 另外，如果replaceAll()和replaceFirst()所用的参数据不是基于规则表达式的，则与replace()替换字符串的效果是一样的，即这两者也支持字符串的操作；
     * 还有一点注意:：执行了替换操作后,源字符串的内容是没有发生改变的。
     */
    @Test
    public void replaceDemo() {
        String name = "韩**";
        String tmp = name.replace("*", "");
        System.out.println(tmp);
        try {
            String tmp2 = name.replaceAll("*", "");
            System.out.println(tmp2);
        } catch (Exception e) {
            e.printStackTrace();
        }

        String s = "{用户姓名}你好！{银行开户行}，借款金额{借款金额}，{逾期天数}，{平台服务费}，{平台服务费}，{到期日},{到期日}";
        s = s.replace("{到期日}", "2017-09-08");
        System.out.println(s);
        String a = "hello,%s";
        System.out.println(String.format(a, 123));

        String xdcsHome = "https://xdcs.ximalaya.com";
        String host1 = xdcsHome.replace("https", "http");
        System.out.println(host1);
    }

    @Test
    public void testMatch() {
        String a = ".*你好.*";
        System.out.println("老王，你好吗".matches(a));
    }

    @Test
    public void testPercentFormat() {
        System.out.println(String.format("%s%%", Math.PI));
        NumberFormat num = NumberFormat.getPercentInstance();
        System.out.println(num.format(Math.PI));
    }

    /**
     * <li>%s 字符串类型
     * <li>%c 字符类型
     * <li>%b 布尔类型
     * <li>%d 整数类型（十进制）
     * <li>%x 整数类型（十六进制）
     * <li>%o 整数类型（八进制）
     * <li>%f 浮点类型
     * <li>%a 十六进制浮点类型
     * <li>%e 指数类型
     * <li>%g 通用浮点类型（f和e类型中较短的）
     * <li>%h 散列码
     * <li>%% 百分比类型
     * <li>%n 换行符
     * <li>%tx 日期与时间类型（x代表不同的日期与时间转换符
     */
    @Test
    public void testFormat() {
        System.out.println(String.format("Hi,%s", "王力"));
        System.out.println(String.format("Hi,%s:%s.%s", "王南", "王力", "王张"));
        System.out.printf("字母a的大写是：%c %n", 'A');
        System.out.printf("3>7的结果是：%b %n", 3 > 7);
        System.out.printf("100的一半是：%d %n", 100 / 2);
        System.out.printf("100的16进制数是：%x %n", 100);
        System.out.printf("100的8进制数是：%o %n", 100);
        System.out.printf("50元的书打8.5折扣是：%f 元%n", 50 * 0.85);
        System.out.printf("上面价格的16进制数是：%a %n", 50 * 0.85);
        System.out.printf("上面价格的指数表示：%e %n", 50 * 0.85);
        System.out.printf("上面价格的指数和浮点数结果的长度较短的是：%g %n", 50 * 0.85);
        System.out.printf("上面的折扣是%d%% %n", 85);
        System.out.printf("字母A的散列码是：%h %n", 'A');
    }


    @Test
    public void testFormatDouble() {
        System.out.println("保留小数点后两位");
        System.out.println(String.format("%.2f", 11.0));
        System.out.println(String.format("%.2f", 1.0));
        System.out.println(String.format("%.2f", 0.1));
        System.out.println(String.format("%.2f", 0.11));
        System.out.println(String.format("%.2f", 0.111));
        System.out.println(String.format("%.2f", 0.1111));
    }

    @Test
    public void testFormatNumber() throws IOException {

        // $使用
        System.out.printf("格式参数$的使用：%1$d,%2$s%n", 99, "abc");
        // +使用
        System.out.printf("显示正负数的符号：%+d与%d%n", 99, -99);
        // 补O使用
        System.out.printf("最牛的编号是：%03d%n", 7);
        // 空格使用
        System.out.printf("Tab键的效果是：% 8d%n", 7);
        // .使用
        System.out.printf("整数分组的效果是：%,d%n", 9989997);
        // 空格和小数点后面个数
        System.out.printf("一本书的价格是：% 20.5f元%n", 49.8);
        System.out.printf("%08d%n", 1);
        System.out.printf("%08f%n", 0.1);
        System.out.printf("%s%n", 1);
        System.out.printf("mx.migrate:%d.%s%n", 1, "a");

        long n = 461012;
        System.out.format("%d%n", n); // --> "461012"
        System.out.format("%08d%n", n); // --> "00461012"
        System.out.format("%+8d%n", n); // --> " +461012"
        System.out.format("%,8d%n", n); // --> " 461,012"
        System.out.format("%+,8d%n%n", n); // --> "+461,012"
        try {
            System.out.printf("%d%n", Float.MIN_VALUE);
        } catch (IllegalFormatConversionException e) {
            System.out.println(e.toString());
        }

        System.out.format("%f%n", Math.PI); // --> "3.141593"
        // 保留3位有效数字
        System.out.format("%.3f%n", Math.PI); // --> "3.142"
        System.out.format("%10.3f%n", Math.PI); // --> " 3.142"
        System.out.format("%-10.3f%n", Math.PI); // --> "3.142"
        System.out.format(Locale.FRANCE, "%-10.4f%n%n", Math.PI); // --> "3,1416"
        try {
            System.out.printf("%f%n", Short.MAX_VALUE);
        } catch (IllegalFormatConversionException e) {
            System.out.println(e);
        }

        Calendar c = Calendar.getInstance();
        System.out.format("%tB %te, %tY%n", c, c, c); // --> "May 29, 2006"

        System.out.format("%tl:%tM %tp%n", c, c, c); // --> "2:34 am"

        System.out.format("%tD%n", c); // --> "05/29/06"

    }

    @Test
    public void formatDate() {
        Date date = new Date();
        // c的使用
        System.out.printf("全部日期和时间信息：%tc%n", date);
        // f的使用
        System.out.printf("年-月-日格式：%tF%n", date);
        // d的使用
        System.out.printf("月/日/年格式：%tD%n", date);
        // r的使用
        System.out.printf("HH:MM:SS PM格式（12时制）：%tr%n", date);
        // t的使用
        System.out.printf("HH:MM:SS格式（24时制）：%tT%n", date);
        // R的使用
        System.out.printf("HH:MM格式（24时制）：%tR", date);

        // b的使用，月份简称
        System.out.println(String.format(Locale.US, "英文月份简称：%tb", date));
        System.out.printf("本地月份简称：%tb%n", date);
        // B的使用，月份全称
        System.out.println(String.format(Locale.US, "英文月份全称：%tB", date));
        System.out.printf("本地月份全称：%tB%n", date);
        // a的使用，星期简称
        System.out.println(String.format(Locale.US, "英文星期的简称：%ta", date));
        // A的使用，星期全称
        System.out.printf("本地星期的简称：%tA%n", date);
        // C的使用，年前两位
        System.out.printf("年的前两位数字（不足两位前面补0）：%tC%n", date);
        // y的使用，年后两位
        System.out.printf("年的后两位数字（不足两位前面补0）：%ty%n", date);
        // j的使用，一年的天数
        System.out.printf("一年中的天数（即年的第几天）：%tj%n", date);
        // m的使用，月份
        System.out.printf("两位数字的月份（不足两位前面补0）：%tm%n", date);
        // d的使用，日（二位，不够补零）
        System.out.printf("两位数字的日（不足两位前面补0）：%td%n", date);
        // e的使用，日（一位不补零）
        System.out.printf("月份的日（前面不补0）：%te", date);

        // H的使用
        System.out.printf("2位数字24时制的小时（不足2位前面补0）:%tH%n", date);
        // I的使用
        System.out.printf("2位数字12时制的小时（不足2位前面补0）:%tI%n", date);
        // k的使用
        System.out.printf("2位数字24时制的小时（前面不补0）:%tk%n", date);
        // l的使用
        System.out.printf("2位数字12时制的小时（前面不补0）:%tl%n", date);
        // M的使用
        System.out.printf("2位数字的分钟（不足2位前面补0）:%tM%n", date);
        // S的使用
        System.out.printf("2位数字的秒（不足2位前面补0）:%tS%n", date);
        // L的使用
        System.out.printf("3位数字的毫秒（不足3位前面补0）:%tL%n", date);
        // N的使用
        System.out.printf("9位数字的毫秒数（不足9位前面补0）:%tN%n", date);
        // p的使用
        System.out.println(String.format(Locale.US, "小写字母的上午或下午标记(英)：%tp", date));
        System.out.printf("小写字母的上午或下午标记（中）：%tp%n", date);
        // z的使用
        System.out.printf("相对于GMT的RFC822时区的偏移量:%tz%n", date);
        // Z的使用
        System.out.printf("时区缩写字符串:%tZ%n", date);
        // s的使用
        System.out.printf("1970-1-1 00:00:00 到现在所经过的秒数：%ts%n", date);
        // Q的使用
        System.out.printf("1970-1-1 00:00:00 到现在所经过的毫秒数：%tQ%n", date);

        System.out.println(String.format("%010d%08d%032d", System.currentTimeMillis() / 1000, Long.valueOf("002220"),
                Math.abs(new Random().nextLong())));
    }

    /**
     * 保留两位小数
     */
    @Test
    public void formatFloat() {
        // 空格和小数点后面个数
        System.out.printf("一本书的价格是：% 50.5f元%n", 49.8);
        System.out.println(String.format("%.2f", Math.PI));
        System.out.println(String.format("%.2f", Math.E));

        String msg = String.format("接口[ %s ]%s响应时间上升[%s]，[%s~%s]期间 %.2f ms，当前[%s~%s] %.2f ms", "/api/a/b", "TP99",
                "52%", "01:00", "01:00", Math.E, "01:00", "01:00", Math.PI);
        System.out.println(msg);
    }

    @Test
    public void regionMatchesDemo() {
        String searchMe = "Green Eggs and Ham";
        String findMe = "Eggs";
        boolean foundIt = false;
        for (int i = 0; i <= (searchMe.length() - findMe.length()); i++) {
            if (searchMe.regionMatches(i, findMe, 0, findMe.length())) {
                foundIt = true;
                System.out.println(searchMe.substring(i, i + findMe.length()));
                break;
            }
        }
        if (!foundIt) {
            System.out.println("No match found.");
        }
    }

    @Test
    public void trigonometricDemo() {
        double degrees = 45.0;
        double radians = Math.toRadians(degrees);

        System.out.format("The value of pi " + "is %.4f%n", Math.PI);

        System.out.format("The sine of %.1f " + "degrees is %.4f%n", degrees, Math.sin(radians));

        System.out.format("The cosine of %.1f " + "degrees is %.4f%n", degrees, Math.cos(radians));

        System.out.format("The tangent of %.1f " + "degrees is %.4f%n", degrees, Math.tan(radians));

        System.out.format("The arcsine of %.4f " + "is %.4f degrees %n", Math.sin(radians),
                Math.toDegrees(Math.asin(Math.sin(radians))));

        System.out.format("The arccosine of %.4f " + "is %.4f degrees %n", Math.cos(radians),
                Math.toDegrees(Math.acos(Math.cos(radians))));

        System.out.format("The arctangent of %.4f " + "is %.4f degrees %n", Math.tan(radians),
                Math.toDegrees(Math.atan(Math.tan(radians))));
    }

    static void exponentialDemo() {
        double x = 11.635;
        double y = 2.76;

        System.out.printf("The value of " + "e is %.4f%n", Math.E);

        System.out.printf("exp(%.3f) " + "is %.3f%n", x, Math.exp(x));

        System.out.printf("log(%.3f) is " + "%.3f%n", x, Math.log(x));

        System.out.printf("pow(%.3f, %.3f) " + "is %.3f%n", x, y, Math.pow(x, y));

        System.out.printf("sqrt(%.3f) is " + "%.3f%n", x, Math.sqrt(x));
    }

    @Test
    public void testMathDemo() {
        double a = -191.635;
        double b = 43.74;
        int c = 16, d = 45;

        System.out.printf("The absolute value " + "of %.3f is %.3f%n", a, Math.abs(a));

        System.out.printf("The ceiling of " + "%.2f is %.0f%n", b, Math.ceil(b));

        System.out.printf("The floor of " + "%.2f is %.0f%n", b, Math.floor(b));

        System.out.printf("The rint of %.2f " + "is %.0f%n", b, Math.rint(b));

        System.out.printf("The max of %d and " + "%d is %d%n", c, d, Math.max(c, d));

        System.out.printf("The min of of %d " + "and %d is %d%n", c, d, Math.min(c, d));
    }

    /*
     * public static void test(){ StringBuilder sb = new StringBuilder(); // Send
     * all output to the Appendable object sb Formatter formatter = new
     * Formatter(sb, Locale.US);
     *
     * // Explicit argument indices may be used to re-order output.
     * formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d") // ->
     * " d  c  b  a"
     *
     * // Optional locale as the first argument can be used to get //
     * locale-specific formatting of numbers. The precision and width can be //
     * given to round and align the value. formatter.format(Locale.FRANCE,
     * "e = %+10.4f", Math.E); // -> "e =    +2,7183"
     *
     * // The '(' numeric flag may be used to format negative numbers with //
     * parentheses rather than a minus sign. Group separators are // automatically
     * inserted. formatter.format(
     * "Amount gained or lost since last statement: $ %(,.2f",balanceDelta); // ->
     * "Amount gained or lost since last statement: $ (6,217.58)" // Writes a
     * formatted string to System.out. System.out.format("Local time: %tT",
     * Calendar.getInstance()); // -> "Local time: 13:34:18"
     *
     * // Writes formatted output to System.err. System.err.printf(
     * "Unable to open file '%1$s': %2$s", fileName, exception.getMessage()); // ->
     * "Unable to open file 'food': No such file or directory"
     *
     * Calendar c = new GregorianCalendar(1995, MAY, 23); String s =
     * String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c); // -> s ==
     * "Duke's Birthday: May 23, 1995" }
     */
    @Test
    public void testASCII() {
        System.out.println("\u7ebf\u4e0a");
        System.out.println("\u5f00\u53d1\u73af\u5883");
        System.out.println("\u6d4b\u8bd5\u73af\u5883");
        System.out.println("\u7ebf\u4e0a");
        String tmp = "abc";
        StringBuilder stringBuilder = new StringBuilder();
        char del = 127;// ASCII码删除符
        System.out.println(del);
        for (int i = 0; i < 9; i++) {
            stringBuilder.append(tmp + i).append(del);
        }
        System.out.println(stringBuilder.toString());

        System.out.println("\u007F");
        System.out.println('a');
        String[] array = stringBuilder.toString().split("\u007F");
        for (String aa : array) {
            System.out.println(aa);
        }
    }

    public static void main(String[] args) {
        String a = "D:/Desktop/a.txt";
        long sum = 0;
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(a))) {
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
                long count = Stream.of(line.split(" ")).filter(s -> s != null && !s.trim().isEmpty()).count();
//                System.out.println(count);
                sum += count;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("sum = " + sum);
        String cn = "你";
        System.out.println(unicode(cn));
        // 字符串 : \u5f00\u59cb\u4efb\u52a1 ，由于 \ 在java里是转义字符，要写出下面这种形式
        String unicode = "\u0049\u0050\u5730\u5740";
        String aa = String.valueOf(unicode);
        System.out.println(aa);
        System.out.println(unicode);
        System.out.println(unicodeToCn(unicode));
    }

    private static String unicodeToCn(String unicode) {
        /** 以 \ u 分割，因为java注释也能识别unicode，因此中间加了一个空格 */
        String[] strs = unicode.split("\\\\u");
        String returnStr = "";
        // 由于unicode字符串以 \ u 开头，因此分割出的第一个字符是""。
        for (int i = 1; i < strs.length; i++) {
            returnStr += (char) Integer.valueOf(strs[i], 16).intValue();
        }
        return returnStr;
    }

    /**
     * 中文转 UNICODE 编码
     *
     * @param cn
     * @return
     */
    public static String unicode(String cn) {
        char[] chars = cn.toCharArray();
        String returnStr = "";
        for (int i = 0; i < chars.length; i++) {
            returnStr += "\\u" + Integer.toString(chars[i], 16);
        }
        return returnStr;
    }

    @Test
    public void indexOf() {
        String m = "sum:rate:proc.stat.cpu{host=foo,type=idle}";
        int tagStart = m.indexOf('{');
        int tagEnd = m.indexOf('}');
        System.out.println("start=" + tagStart + " ,end=" + tagEnd);
        Map<String, String> tagMap = new HashMap<>();
        if (tagStart >= 0 && tagStart < tagEnd) {
            String tags = m.substring(tagStart + 1, tagEnd);
            System.out.println(tags);
            for (String tagValueStr : tags.split(",")) {
                String[] tv = tagValueStr.split("=");
                tagMap.put(tv[0], tv[1]);
            }
        }
        System.out.println("tags = " + tagMap.toString());
        String metricStr = tagStart > 0 ? m.substring(0, tagStart) : m;
        String[] array = metricStr.split(":");
        String metricName;
        String aggregator;
        boolean rate;
        if (array.length == 1) {
            metricName = array[0];
            rate = false;
            aggregator = "none";
        } else if (array.length == 2) {
            metricName = array[1];
            rate = false;
            aggregator = array[0];
        } else {
            metricName = array[2];
            rate = "rate".equals(array[1]);
            aggregator = array[0];
        }
        System.out.println("metric=" + metricName + ",rate=" + rate + ",aggregator=" + aggregator);
    }

    @Test
    public void testLastIndexOf() {
        String podStr = "thanos-query-6d87bf6f85-6r9jj";
        String app = StringUtils.substring(podStr, 0, podStr.lastIndexOf('-'));
        app = StringUtils.substring(app, 0, app.lastIndexOf('-'));
        System.out.println(app);
    }

    /**
     * 首字母大写
     *
     * @param string
     * @return
     */
    public static String upperCase1stLetter(String string) {
        if (null == string) {
            return "";
        }
        // string = string.substring(0, 1).toUpperCase() + string.substring(1);
        // return string;
        char[] cs = string.toCharArray();
        if (97 <= cs[0] && cs[0] <= 122) {// 小写字母ASCII码区间
            cs[0] -= 32;
            return String.valueOf(cs);
        }
        return string;
    }

    /**
     * 首字母小写
     *
     * @param string
     * @return
     */
    public static String lowerCase1stLetter(String string) {
        if (null == string) {
            return "";
        }
        char[] cs = string.toCharArray();
        if (65 <= cs[0] && cs[0] <= 90) {// 大写字母ASCII码区间
            cs[0] += 32;
            return String.valueOf(cs);
        }
        return string;
    }

    /**
     * 标准的Java命名规范（驼峰形式）
     *
     * @param name
     * @return
     */
    public static String javaNamingConvention(String name) {
        if (name == null || name.isEmpty()) {
            return null;
        }
        String[] array = name.split("_");
        StringBuilder convention = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            String tmp = array[i];
            if (i == 0) {
                convention.append(lowerCase1stLetter(tmp));
            } else {
                convention.append(upperCase1stLetter(tmp));
            }

        }
        return convention.toString();
    }


    /**
     * 用ascii码判断是否为数字
     *
     * @param str
     * @return
     */
    public static boolean isNumeric(String str) {
        for (int i = str.length(); --i >= 0; ) {
            int chr = str.charAt(i);
            if (chr < 48 || chr > 57) {
                return false;
            }
        }
        return true;
    }

    @Test
    public void testJoin() {
        System.out.println(StringUtils.join(Arrays.asList("a", "b"), StringUtils.LF));
        System.out.println(StringUtils.join(Arrays.asList("a", "b"), StringUtils.CR));
        System.out.println(StringUtils.join(Arrays.asList("a", "b"), "\r\n"));

    }

    private static void testAppend() {
        Runtime runtime = Runtime.getRuntime();
        long memory;
        long prev_time;
        int i;
        long time;
        StringBuilder sb = new StringBuilder();
        memory = runtime.freeMemory();
        prev_time = System.currentTimeMillis();
        for (i = 0; i < 10000; i++) {
            sb.append("Blah ");
            sb.append(i);
            sb.append("Blah ");
            sb.append(i);
            sb.append("Blah ");
            sb.append(i);
        }
        time = System.currentTimeMillis() - prev_time;
        memory = memory - runtime.freeMemory();
        System.out.println("Time: " + time + "    Memory Usage: " + memory);
    }


    /**
     * 字节数组转字符串
     *
     * @param bytes
     * @return
     */
    public static String byte2Str(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        try {
            return new String(bytes, UTF8);
        } catch (UnsupportedEncodingException e) {
            return new String(bytes);
        }
    }

    /**
     * 字节数组转字符串
     *
     * @param bytes
     * @return
     */
    private static String[] byte2Str(byte[][] bytes) {
        if (bytes == null) {
            return null;
        }
        String[] result = new String[bytes.length];
        for (int i = 0; i < bytes.length; i++) {
            result[i] = byte2Str(bytes[i]);
        }
        return result;
    }

    @Test
    public void testByte2Str() {
        System.out.println("".equals(byte2Str(new byte[0])));
        String[] a = null;
        System.out.println(Arrays.toString(a));
    }

    /**
     * 文本块允许多行字符串的书写更加直观，减少了转义字符的需求
     */
    @Test
    public void testTextBlocks() {
        String html = """
                <html>
                    <body>
                        Hello, World!
                    </body>
                </html>
                """;
        System.out.println(html);
    }

    @Test
    public void testEmoji() {
        //  小人头举手报告
        String str = "\uD83D\uDE4B";
        System.out.println(str);

        //  文本报告
        str = "\uD83D\uDCDD";
        System.out.println(str);
        // 用户虚影
        str = "\uD83D\uDC64";
        System.out.println(str);

        //  时间
        str = "\uD83D\uDD50";
        System.out.println(str);

        //  闹钟
        str = "\uD83D\uDD52";
        System.out.println(str);

        //  红点
        str = "\uD83D\uDD34";
        System.out.println(str);

        //  蓝点
        str = "\uD83D\uDD35";
        System.out.println(str);

        //  黄色菱形
        str = "\uD83D\uDD36";
        System.out.println(str);

        //  蓝色菱形
        str = "\uD83D\uDD37";
        System.out.println(str);

        //  金色警钟
        str = "\uD83D\uDD14";
        System.out.println(str);
    }
}

